#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2020 Huawei Technologies Co., Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import acl
import sys
import numpy as np
import cv2
from queue import Queue
sys.path.append("..")
from resource.resource import ascend_resource
from common.log import Log, check_ret
from common.const import ACL_MEMCPY_HOST_TO_HOST, \
                     ACL_MEMCPY_HOST_TO_DEVICE, \
                     ACL_MEMCPY_DEVICE_TO_HOST, \
                     ACL_MEMCPY_DEVICE_TO_DEVICE, \
                     PIXEL_FORMAT_YUV_SEMIPLANAR_420, \
                     PIXEL_FORMAT_YVU_SEMIPLANAR_420, \
                     PIXEL_FORMAT_YUV_SEMIPLANAR_422, \
                     PIXEL_FORMAT_YVU_SEMIPLANAR_422, \
                     PIXEL_FORMAT_YUV_SEMIPLANAR_444, \
                     PIXEL_FORMAT_YVU_SEMIPLANAR_444, \
                     DEBUG, INFO, WARNING, ERROR, \
                     DVPP, DEVICE, HOST


class DvppInfo():
    def __init__(self, copied_object = None):
        if isinstance(copied_object, DvppInfo):
            self.buffer_ptr = copied_object.buffer_ptr
            self.buffer_size = copied_object.buffer_size
            self.width = copied_object.width
            self.height = copied_object.height
            self.aligned_width = copied_object.aligned_width
            self.aligned_height = copied_object.aligned_height
            self.pic_format = copied_object.pic_format
            self.context = copied_object.context
            self.frame_id = copied_object.frame_id
            self.channel_id = copied_object.channel_id
        else:
            self.buffer_ptr = 0
            self.buffer_size = 0
            self.width = 0
            self.height = 0
            self.aligned_width = 0
            self.aligned_height = 0
            self.pic_format = 0
            self.context = 0
            self.frame_id = 0
            self.channel_id = 0
    def reset(self):
        self.buffer_ptr = 0
        self.buffer_size = 0
        self.width = 0
        self.height = 0
        self.aligned_width = 0
        self.aligned_height = 0
        self.pic_format = 0
        self.context = 0
        self.frame_id = 0
        self.channel_id = 0


class AscendDvpp():
    def __init__(self, context, stream):
        self.class_name = self.__class__.__name__
        self.context = context
        self.stream = stream
        self._dvpp_channel_desc = None
        self.memory = ascend_resource.memory_pool
        self.resource = ascend_resource.resource_manager
        self._resize_config = None
        self.roi_desc = {'crop': None, 'paste': None}
        self.jpegd_decode_desc = {'output': None}
        self.resize_desc = {'input': None, 'output': None}
        self.crop_desc = {'input': None, 'output': None}
        self.crop_and_paste_desc = {'input': None, 'output': None}

        self.init_dvpp_in_current_context()
        
    def create_pic_channel(self):
        self._dvpp_channel_desc = acl.media.dvpp_create_channel_desc()
        ret = acl.media.dvpp_create_channel(self._dvpp_channel_desc)
        check_ret(self.class_name, 'create_pic_channel', 'create channel fail', ret)

    def init_dvpp_in_current_context(self):
        self.resource.set_current_context(self.context)
        self.create_pic_channel()
        Log.do_log(INFO, self.class_name, 'init_dvpp_in_current_context', 'AscendDvpp Init Success')

    def gen_pic_des(self, dvpp_info: DvppInfo):
        pic_desc = acl.media.dvpp_create_pic_desc()
        ret = acl.media.dvpp_set_pic_desc_data(pic_desc, dvpp_info.buffer_ptr)
        check_ret(self.class_name, 'gen_pic_des', 'fail to set pic desc data', ret)
        ret = acl.media.dvpp_set_pic_desc_size(pic_desc, dvpp_info.buffer_size)
        check_ret(self.class_name, 'gen_pic_des', 'fail to set pic sesc size', ret)
        ret = acl.media.dvpp_set_pic_desc_format(pic_desc, dvpp_info.pic_format)
        check_ret(self.class_name, 'gen_pic_des', 'fail to set pic sesc format', ret)
        ret = acl.media.dvpp_set_pic_desc_width(pic_desc, dvpp_info.width)
        check_ret(self.class_name, 'gen_pic_des', 'fail to set pic sesc width', ret)
        ret = acl.media.dvpp_set_pic_desc_height(pic_desc, dvpp_info.height)
        check_ret(self.class_name, 'gen_pic_des', 'fail to set pic sesc height', ret)
        ret = acl.media.dvpp_set_pic_desc_width_stride(pic_desc, dvpp_info.aligned_width)
        check_ret(self.class_name, 'gen_pic_des', 'fail to set pic sesc width stride', ret)
        ret = acl.media.dvpp_set_pic_desc_height_stride(pic_desc, dvpp_info.aligned_height)
        check_ret(self.class_name, 'gen_pic_des', 'fail to set pic sesc height stride', ret)
        return pic_desc

    def jpeg_decode(self, input_desc:DvppInfo, output_format:int):
        output_desc = DvppInfo(copied_object = input_desc)
        output_desc.context = self.context
        output_desc.buffer_ptr, output_desc.buffer_size, \
        output_desc.aligned_width, output_desc.aligned_height\
            = self.memory.memory_allocation('jpegd', 
                                            input_desc.height, 
                                            input_desc.width, 
                                            output_format)
        self.jpegd_decode_desc['output'] = self.gen_pic_des(output_desc)
        ret = acl.media.dvpp_jpeg_decode_async(self._dvpp_channel_desc,
                                               input_desc.buffer_ptr,
                                               input_desc.buffer_size,
                                               self.jpegd_decode_desc['output'],
                                               self.stream)
        check_ret(self.class_name, 'jpeg_decode', 'fail to send jpeg msg', ret)
        ret = acl.rt.synchronize_stream(self.stream)
        check_ret(self.class_name, 'jpeg_decode', 'fail to finish stream', ret)
        self.free_dvpp_pic_desc()
        Log.do_log(INFO, self.class_name, 'jpeg_decode', 'Jpegd success')
        return output_desc

    def resize(self, input_desc:DvppInfo, width, height, output_format):
        # create vpc resize input desc
        width_stride, height_stride = self.memory.stride_calculation(input_desc.aligned_height, 
                                                                     input_desc.aligned_width, 
                                                                     'resize')
        buffer_size = self.memory.buffer_size_calculation(width_stride, height_stride, 
                                                          output_format)
        if buffer_size > input_desc.buffer_size:
            Log.do_log(ERROR, self.class_name, 'resize', 'aligned image size is larger than input image size')  
        self.resize_desc['input'] = self.gen_pic_des(input_desc)
        #create vpc resize output desc
        output_desc = DvppInfo()
        output_desc.pic_format = output_format
        output_desc.width = width
        output_desc.height = height
        output_desc.buffer_ptr, output_desc.buffer_size, \
        output_desc.aligned_width, output_desc.aligned_height\
            = self.memory.memory_allocation('resize', 
                                            height, 
                                            width, 
                                            output_format)
        self.resize_desc['output'] = self.gen_pic_des(output_desc)
        #config
        self._resize_config = acl.media.dvpp_create_resize_config()
        #resize
        ret = acl.media.dvpp_vpc_resize_async(self._dvpp_channel_desc,
                                              self.resize_desc['input'],
                                              self.resize_desc['output'],
                                              self._resize_config,
                                              self.stream)
        check_ret(self.class_name, 'resize', 'fail to send resize msg', ret)
        ret = acl.rt.synchronize_stream(self.stream)
        check_ret(self.class_name, 'resize', 'fail to finish stream', ret)
      
        output_desc.frame_id = input_desc.frame_id
        output_desc.channel_id = input_desc.channel_id
        output_desc.context = self.context
        self.free_dvpp_pic_desc()
        self.free_dvpp_config()
        Log.do_log(INFO, self.class_name, 'resize', 'Resize success')
        return output_desc

    def crop(self, input_desc:DvppInfo,
             left_width, right_width,
             top_height, bottom_height,
             output_format):
        # create input picture description
        width_stride, height_stride = self.memory.stride_calculation(input_desc.height, 
                                                                     input_desc.width, 
                                                                     'crop')
        buffer_size = self.memory.buffer_size_calculation(width_stride, height_stride, 
                                                          self.input_desc.data_format)
        if buffer_size > self.input_desc.buffer_size:
            Log.do_log(ERROR, self.class_name, 'resize', 'aligned image size is larger than input image size')
        self.crop_desc['input'] = self.gen_pic_des(input_desc)
        # create output picture description
        output_desc = DvppInfo(input_desc)
        output_desc.pic_format = output_format
        output_desc.width = right_width - left_width
        output_desc.height = bottom_height - top_height
        output_desc.buffer_ptr, output_desc.buffer_size,\
        output_desc.aligned_width, output_desc.aligned_height \
            = self.memory.memory_allocation('crop', 
                                            output_desc.height, 
                                            output_desc.width, 
                                            output_desc.pic_format)
        self.crop_desc['output'] = self.gen_pic_des(output_desc)

        # create roi description
        self.roi_desc['crop'] = acl.media.dvpp_create_roi_config(left_width, right_width,
                                                                 top_height, bottom_height)
        # crop processing
        ret = acl.media.dvpp_vpc_crop_async(self._dvpp_channel_desc,
                                            self.crop_desc['input'],
                                            self.crop_desc['output'],
                                            self.roi_desc['crop'],
                                            self.stream)
        check_ret(self.class_name, 'crop', 'fail to send info to vpc crop', ret)
        ret = acl.rt.synchronize_stream(self.stream)
        check_ret(self.class_name, 'crop', 'fail to process crop', ret)
        self.free_dvpp_pic_desc()
        Log.do_log(INFO, self.class_name, 'crop', 'vpc crop process success')
        return output_desc

    def crop_and_paste(self, input_desc:DvppInfo, 
                       crop_left_width, crop_right_width, 
                       crop_top_height, crop_bottom_height,
                       paste_left_width, paste_right_width, 
                       paste_top_height, paste_bottom_height,
                       width, height, output_format):
        # create input picture description
        width_stride, height_stride = self.memory.stride_calculation(input_desc.height, 
                                                                     input_desc.width, 
                                                                     'crop_and_paste')
        buffer_size = self.memory.buffer_size_calculation(width_stride, height_stride, 
                                                          input_desc.pic_format)
        if buffer_size > input_desc.buffer_size:
            Log.do_log(ERROR, self.class_name, 'crop_and_paste', 'aligned image size is larger than input image size')
        self.crop_and_paste_desc['input'] = self.gen_pic_des(input_desc)

        # create output picture description
        output_desc = DvppInfo(input_desc)
        output_desc.pic_format = output_format
        output_desc.width = width
        output_desc.height = height
        output_desc.buffer_ptr, output_desc.buffer_size, \
        output_desc.aligned_width, output_desc.aligned_height\
            = self.memory.memory_allocation('crop_and_paste',
                                           output_desc.height,
                                           output_desc.width,
                                           output_desc.pic_format)
        self.crop_and_paste_desc['output'] = self.gen_pic_des(output_desc)
        self.roi_desc['crop'] = acl.media.dvpp_create_roi_config(crop_left_width, crop_right_width, 
                                                                 crop_top_height, crop_bottom_height)
        if paste_left_width % 16:
            Log.do_log(ERROR, self.class_name, 'crop_and_paste', 'paste_left_width has to be aligned by 16')
        if not(paste_right_width % 2 and paste_bottom_height % 2):
            Log.do_log(ERROR, self.class_name, 'crop_and_paste', 'paste_right_width and paste_bottom_height must be odd')
        if paste_left_width % 2 and paste_top_height % 2:
            Log.do_log(ERROR, self.class_name, 'crop_and_paste', 'paste_left_width and paste_top_height must be even')

        self.roi_desc['paste'] = acl.media.dvpp_create_roi_config(paste_left_width, paste_right_width, 
                                                                  paste_top_height, paste_bottom_height)
        ret = acl.media.dvpp_vpc_crop_and_paste_async(self._dvpp_channel_desc,
                                                      self.crop_and_paste_desc['input'],
                                                      self.crop_and_paste_desc['output'],
                                                      self.roi_desc['crop'],
                                                      self.roi_desc['paste'],
                                                      self.stream)
        check_ret(self.class_name, 'crop_and_paste', 'fail to send info to vpc crop and paste', ret)
        ret = acl.rt.synchronize_stream(self.stream)
        check_ret(self.class_name, 'crop_and_paste', 'fail to process crop and paste', ret)
        self.free_dvpp_pic_desc()
        self.free_dvpp_config()
        Log.do_log(INFO, self.class_name, 'crop', 'vpc crop and paste process success')
        return output_desc

    def resize_crop_paste_with_same_ratio(self, input_desc:DvppInfo, width, height, output_format):
        if input_desc.width > input_desc.height:
            ratio = input_desc.height / input_desc.width
            resize_width = width
            resize_height = int(height * ratio)
            if resize_height % 2:
                resize_height += 1            
        elif input_desc.width < input_desc.height:
            ratio = input_desc.width / input_desc.height
            resize_height = height
            resize_width = int(width * ratio)
            if resize_width % 2:
                resize_width += 1
        else:
            Log.do_log(WARNING, self.class_name, 'resize_crop_paste_with_same_ratio', 'resize function is satisfied')
            output_desc = self.resize(input_desc, width, height, output_format)
            return output_desc
        resize_desc = self.resize(input_desc, resize_width, resize_height, output_format)
        output_desc = self.crop_and_paste(resize_desc,
                        0, resize_width - 1,
                        0, resize_height - 1,
                        0, resize_width - 1,
                        0, resize_height - 1,
                        width, height,
                        output_format)      
        self.memory.release_memory(resize_desc.buffer_ptr, DVPP) 
        return output_desc

    def free_dvpp_resource(self, dvpp_info:DvppInfo):
        if dvpp_info.buffer_ptr:
            self.memory.release_memory(dvpp_info.buffer_ptr, DVPP)
            dvpp_info.reset()

    def free_dvpp_pic_desc(self):
        if self.jpegd_decode_desc['output']:
            acl.media.dvpp_destroy_pic_desc(self.jpegd_decode_desc['output'])
            self.jpegd_decode_desc['output'] = None
        if self.resize_desc['input']:
            acl.media.dvpp_destroy_pic_desc(self.resize_desc['input'])
            self.resize_desc['input'] = None
        if self.resize_desc['output']:
            acl.media.dvpp_destroy_pic_desc(self.resize_desc['output'])
            self.resize_desc['output'] = None
        if self.crop_desc['input']:
            acl.media.dvpp_destroy_pic_desc(self.crop_desc['input'])
            self.crop_desc['input'] = None
        if self.crop_desc['output']:
            acl.media.dvpp_destroy_pic_desc(self.crop_desc['output'])
            self.crop_desc['output'] = None

        if self.crop_and_paste_desc['input']:
            acl.media.dvpp_destroy_pic_desc(self.crop_and_paste_desc['input'])
            self.crop_and_paste_desc['input'] = None
        if self.crop_and_paste_desc['output']:
            acl.media.dvpp_destroy_pic_desc(self.crop_and_paste_desc['output'])
            self.crop_and_paste_desc['output'] = None

    def free_dvpp_config(self):
        if self._resize_config:
            acl.media.dvpp_destroy_resize_config(self._resize_config)
            self._resize_config = None
        
        if self.roi_desc['crop']:
            acl.media.dvpp_destroy_roi_config(self.roi_desc['crop'])
            self.roi_desc['crop'] = None

        if self.roi_desc['paste']:
            acl.media.dvpp_destroy_roi_config(self.roi_desc['paste'])
            self.roi_desc['paste'] = None

    def free_dvpp_channel_desc(self):
        if self._dvpp_channel_desc:
            acl.media.dvpp_destroy_channel(self._dvpp_channel_desc)
            acl.media.dvpp_destroy_channel_desc(self._dvpp_channel_desc)

    def free_dvpp(self, context_id=None):
        if context_id is not None:
            ret = acl.rt.set_context(context_id)
        self.free_dvpp_pic_desc()
        self.free_dvpp_config()
        self.free_dvpp_channel_desc()

class AscendVdec():
    def __init__(self, context, stream, channel_id, _en_type, pic_format, q_for_callback):
        self.class_name = self.__class__.__name__
        # resource
        self.context = context
        self.stream = stream
        self.memory = ascend_resource.memory_pool
        # channel desc
        self.vdec_channel_desc = 0
        self.cb_thread_id = 0
        self._en_type = _en_type
        self._format = pic_format
        self._channel_id = channel_id
        self.frame_config = None
        # call_back
        self.q = q_for_callback
        # vdec init
        self._vdec_exit = True
        self.init_thread(timeout=10)
        self.init_vdec_channel_resource()

    def init_thread(self, timeout=1):
        self.cb_thread_id, ret = acl.util.start_thread(self._thread_func, [timeout])
        check_ret(self.class_name, 'init_thread', 'fail to start thread by acl', ret)

    def _thread_func(self, args_list):
        timeout = args_list[0]
        acl.rt.set_context(self.context)
        while self._vdec_exit:
            acl.rt.process_report(timeout)
        Log.do_log(INFO, self.class_name, '_thread_func', 'vdec_thread_func out')

    def _callback(self, input_stream_desc, output_pic_desc, user_data):
        # input_pic_desc
        if input_stream_desc:
            Log.do_log(INFO, self.class_name, '_callback', 'release input stream desc')
            ptr = acl.media.dvpp_get_stream_desc_data(input_stream_desc)
            self.memory.release_memory(ptr, DVPP)
            ret = acl.media.dvpp_destroy_stream_desc(input_stream_desc)
            check_ret(self.class_name, '_callback', 'fail to destroy input stream desc', ret)
        # output_pic_desc
        if output_pic_desc:
            Log.do_log(INFO, self.class_name, '_callback', 'release output stream desc')
            ret = acl.media.dvpp_get_pic_desc_ret_code(output_pic_desc)
            
            if ret != 0:
                Log.do_log(WARNING, self.class_name, '_callback', 'something wrong(ret {})'.format(ret))
                ptr = acl.media.dvpp_get_pic_desc_data(output_pic_desc)
                self.memory.release_memory(ptr, DVPP)
                ret = acl.media.dvpp_destroy_pic_desc(output_pic_desc)
                check_ret(self.class_name, '_callback', 'fail to destory output pic desc', ret)
            else:
                Log.do_log(INFO, self.class_name, '_callback', 'vdec decode success')
                if not self.q.full():
                    pic = DvppInfo()
                    pic.buffer_ptr = acl.media.dvpp_get_pic_desc_data(output_pic_desc)
                    pic.buffer_size = acl.media.dvpp_get_pic_desc_size(output_pic_desc)
                    pic.aligned_width = acl.media.dvpp_get_pic_desc_width_stride(output_pic_desc)
                    pic.aligned_height = acl.media.dvpp_get_pic_desc_height_stride(output_pic_desc)
                    pic.pic_format = acl.media.dvpp_get_pic_desc_format(output_pic_desc)
                    pic.width = acl.media.dvpp_get_pic_desc_width(output_pic_desc)
                    pic.height = acl.media.dvpp_get_pic_desc_height(output_pic_desc)
                    pic.channel_id = user_data[0]
                    pic.frame_id = user_data[1]
                    self.q.put(pic)
                    ret = acl.media.dvpp_destroy_pic_desc(output_pic_desc)
                    check_ret(self.class_name, '_callback', 'fail to destory output pic desc', ret)
                    Log.do_log(INFO, self.class_name, '_callback', 'callback quit success')               
                else:
                    Log.do_log(WARNING, self.class_name, '_callback', 'vdec queue is full')
                    ptr = acl.media.dvpp_get_pic_desc_data(output_pic_desc)
                    self.memory.release_memory(ptr, DVPP)  
                    ret = acl.media.dvpp_destroy_pic_desc(output_pic_desc)
                    check_ret(self.class_name, '_callback', 'fail to destory output pic desc', ret)

    def init_vdec_channel_resource(self):
        self.vdec_channel_desc = acl.media.vdec_create_channel_desc()
        ret = acl.media.vdec_set_channel_desc_channel_id(self.vdec_channel_desc, self._channel_id)
        check_ret(self.class_name, 'init_vdec_channel_resource', 'fail to set channel desc channel id', ret)
        ret = acl.media.vdec_set_channel_desc_thread_id(self.vdec_channel_desc, self.cb_thread_id)
        check_ret(self.class_name, 'init_vdec_channel_resource', 'fail to set channel desc thread id', ret)
        ret = acl.media.vdec_set_channel_desc_callback(self.vdec_channel_desc, self._callback)
        check_ret(self.class_name, 'init_vdec_channel_resource', 'fail to set channel desc call back', ret)
        ret = acl.media.vdec_set_channel_desc_entype(self.vdec_channel_desc, self._en_type)
        check_ret(self.class_name, 'init_vdec_channel_resource', 'fail to set channel en_type', ret)
        ret = acl.media.vdec_set_channel_desc_out_pic_format(self.vdec_channel_desc, self._format)
        check_ret(self.class_name, 'init_vdec_channel_resource', 'fail to set channel desc format', ret)
        ret = acl.media.vdec_create_channel(self.vdec_channel_desc)
        check_ret(self.class_name, 'init_vdec_channel_resource', 'fail to create channel desc', ret)
        self.frame_config = acl.media.vdec_create_frame_config()
        Log.do_log(INFO, self.class_name, 'init_vdec_channel_resource', 'Vdec init success')

    def tranfer_data_to_device(self, input_ptr, img_ptr, img_buffer_size):
        ret = acl.rt.memcpy(input_ptr,
                            img_buffer_size,
                            img_ptr,
                            img_buffer_size,
                            ACL_MEMCPY_HOST_TO_DEVICE)
        check_ret(self.class_name, 'tranfer_data_to_device', 'fail to tranfer data from host to device', ret)
        #self.memory.release_memory(img_ptr, HOST)

    def tranfer_data_to_host(self, output_ptr, img_ptr, img_buffer_size):
        ret = acl.rt.memcpy(output_ptr,
                            img_buffer_size,
                            img_ptr,
                            img_buffer_size,
                            ACL_MEMCPY_DEVICE_TO_HOST)
        check_ret(self.class_name, 'tranfer_data_to_host', 'fail to tranfer data from device to host', ret)

    def _set_input(self, input_stream_ptr, input_stream_size):
        dvpp_stream_desc = acl.media.dvpp_create_stream_desc()
        ret = acl.media.dvpp_set_stream_desc_data(dvpp_stream_desc, input_stream_ptr)
        check_ret(self.class_name, '_set_input', 'fail to set stream desc data', ret)
        ret = acl.media.dvpp_set_stream_desc_size(dvpp_stream_desc, input_stream_size)
        check_ret(self.class_name, '_set_input', 'fail to set stream desc size', ret)
        Log.do_log(INFO, self.class_name, '_set_input', 'set input success')
        return dvpp_stream_desc

    def _set_pic_output(self, height, width):
        buffer_ptr, buffer_size, _, _ = \
               self.memory.memory_allocation('vdec', height, width, self._format)
        # pic_desc
        dvpp_pic_desc = acl.media.dvpp_create_pic_desc()
        ret = acl.media.dvpp_set_pic_desc_data(dvpp_pic_desc, buffer_ptr)
        check_ret(self.class_name, '_set_pic_output', 'fail to set pic desc data', ret)
        ret = acl.media.dvpp_set_pic_desc_size(dvpp_pic_desc, buffer_size)
        check_ret(self.class_name, '_set_pic_output', 'fail to set pic desc size', ret)
        ret = acl.media.dvpp_set_pic_desc_format(dvpp_pic_desc, self._format)
        check_ret(self.class_name, '_set_pic_output', 'fail to set pic desc format', ret)
        Log.do_log(INFO, self.class_name, '_set_pic_output', 'set output success')
        return dvpp_pic_desc

    def forward(self, input_stream_ptr, input_stream_size, height, width, frame_id, channel_id):
        dvpp_stream_desc = self._set_input(input_stream_ptr, input_stream_size)
        dvpp_pic_desc = self._set_pic_output(height, width)
        # vdec_send_frame
        ret = acl.media.vdec_send_frame(self.vdec_channel_desc,
                                            dvpp_stream_desc,
                                            dvpp_pic_desc,
                                            self.frame_config,
                                            (channel_id, frame_id))
        check_ret(self.class_name, '_set_pic_output', 'fail to send frame', ret)

    def imread(self, input_data: DvppInfo, data_from='host'):
        Log.do_log(INFO, self.class_name, 'imread', 'start to vdec')
        if data_from == 'host':
            # set input memory at device
            input_stream_ptr = self.memory.memory_allocation_(input_data.buffer_size, DVPP)
            # from host to device
            self.tranfer_data_to_device(input_stream_ptr, input_data.buffer_ptr, input_data.buffer_size)
        else:
            input_stream_ptr = input_data.buffer_ptr
        # vdec process at device
        self.forward(input_stream_ptr, input_data.buffer_size, 
                     input_data.height, input_data.width, 
                     input_data.frame_id, input_data.channel_id)
        Log.do_log(INFO, self.class_name, 'imread', 'end to vdec')

    def destroy_resource(self,context_id=None):
        if context_id is not None:
            ret = acl.rt.set_context(context_id)
        ret = acl.media.vdec_destroy_channel(self.vdec_channel_desc)
        check_ret(self.class_name, 'destroy_resource', 'fail to destory channel', ret)
        ret = acl.media.vdec_destroy_channel_desc(self.vdec_channel_desc)
        check_ret(self.class_name, 'destroy_resource', 'fail to destory channel desc', ret)
        ret = acl.media.vdec_destroy_frame_config(self.frame_config)
        check_ret(self.class_name, 'destroy_resource', 'fail to destory frame config', ret)
        self._vdec_exit = False
        ret = acl.util.stop_thread(self.cb_thread_id)
        check_ret(self.class_name, 'destroy_resource', 'fail to stop thread', ret)
